﻿
Imports std
Imports lock_t = lock(Of locks.monitorlock)

Public Class pool3(Of T, _THREADSAFE As _boolean)
    Private Shared _tf As Boolean = False
    Private Shared POOL3_LENGTH As Int64
    Private fl As lock_t
    Private f As queue(Of pointer(Of T)) = Nothing
    Private al As lock_t
    Private a As vector(Of pointer(Of T)) = Nothing
    Private _clearing As Boolean = False

    Shared Sub New()
        _tf = +(alloc(Of _THREADSAFE)())
        POOL3_LENGTH = counter.register(GetType(T).FullName().ToUpper() + "_POOL3_LENGTH")
    End Sub

    Private Shared Function threadsafe() As Boolean
        Return _tf
    End Function

    Public Sub New()
        f = New queue(Of pointer(Of T))()
        a = New vector(Of pointer(Of T))()
    End Sub

    Protected Function clearing()
        Return _clearing
    End Function

    Private Sub lockf()
        If threadsafe() Then
            fl.wait()
        End If
    End Sub

    Private Sub unlockf()
        If threadsafe() Then
            fl.release()
        End If
    End Sub

    Private Sub locka()
        If threadsafe() Then
            al.wait()
        End If
    End Sub

    Private Sub unlocka()
        If threadsafe() Then
            al.release()
        End If
    End Sub

    Public Function [get]() As T
        Dim rtn As pointer(Of T) = Nothing
        If Not f.empty() Then
            lockf()
            If Not f.empty() Then
                rtn = f.front()
                assert(f.pop())
            End If
            unlockf()
        End If
        If rtn Is Nothing Then
            rtn = New pointer(Of T)(create())
            assert(Not rtn Is Nothing AndAlso Not +rtn Is Nothing)
            counter.increase(POOL3_LENGTH)
            locka()
            assert(a.push_back(rtn))
            unlocka()
        End If
        tie(+rtn)
        Return +rtn
    End Function

    Private Sub confirmCreator(ByVal i As T)
        If isdebugmode() Then
            Dim j As Int64
            j = a.size() - 1
            For j = j To 0 Step -1
                If object_compare(+a(j), i) = 0 Then
                    Exit For
                End If
            Next
            assert(j >= 0, "object released to pool3 is not created by pool3")
        End If
    End Sub

    Public Sub release(ByVal i As T)
        If i Is Nothing Then
            raiseError(errorHandle.errorType.exclamation,
                       "released an empty object into pool3, callstack ", callstack())
        Else
            free(i)
            confirmCreator(i)
            Dim p As pointer(Of T) = Nothing
            p = New pointer(Of T)(i)
            lockf()
            assert(f.push(p))
            unlockf()
        End If
    End Sub

    Public Sub clear()
        _clearing = True
        For i As Int64 = 0 To a.size() - 1
            If Not a(i) Is Nothing Then
                [erase](+a(i))
                counter.decrease(POOL3_LENGTH)
            End If
        Next
        a.clear()
        f.clear()
        _clearing = False
    End Sub

    Protected Overridable Function create() As T
        Return alloc(Of T)()
    End Function

    Protected Overridable Sub [erase](ByRef inst As T)
        inst = Nothing
    End Sub

    Protected Overridable Sub tie(ByVal inst As T)
    End Sub

    Protected Overridable Sub free(ByVal inst As T)
    End Sub
End Class

Public Class pool3(Of T)
    Inherits pool3(Of T, _true)
End Class